package com.springblog.oauth2;


import com.springblog.entity.UserEntity;
import com.springblog.exception.CoolException;
import com.springblog.service.UserService;
import com.springblog.common.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


/**
 * 认证
 * Realm 用于处理用户是否合法
 */
@Component
public class OAuth2Realm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private JwtUtils jwtUtils;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof OAuth2Token;
    }

    /**
     * 授权(验证权限时调用)
     * 由于此处并不左权限控制，因此直接返回 null 即可
     * <p>
     * 授权认证,设置角色/权限信息
     * <p>
     * 只有当需要检测用户权限的时候才会调用此方法，例如checkRole,checkPermission之类的
     * Shiro+JWT的授权过程和单独使用Shiro的授权过程是一样的。唯一的区别是在查询用户权限时，
     * 需要的用户ID不能从Session中获取的，而是从Subject取出存进去的token，将token进行解析得到其中的id。
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("doGetAuthorizationInfo==============进行权限授权时触发: " + principalCollection);
//        User userEntity = (User) principalCollection.getPrimaryPrincipal();
//        Long userId = userEntity.getId();
//
//        System.out.println("==============userId: " + userId);
//
//        // 权限校验
//        Set<String> permsSet = new HashSet<>();
//        permsSet.add("user:info");
//
//        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//        info.setStringPermissions(permsSet);
        return null;
    }

    /**
     * 认证
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        String accessToken = (String) authenticationToken.getPrincipal();
        Claims claims = jwtUtils.getClaimByToken(accessToken);

        if (claims == null || jwtUtils.isTokenExpired(claims.getExpiration())) {
            throw new CoolException("token失效，请重新登录");
        }

        String userId = (String) claims.getSubject();

        UserEntity userEntity = userService.getById(userId);

        if (userEntity == null) {
            System.out.println("账户不存在");
            throw new CoolException("账户不存在！");
        }

        if (userEntity.getStatus() == 0) {
            throw new CoolException("账户已被锁定！");
        }

        return new SimpleAuthenticationInfo(userEntity, accessToken, getName());
    }
}
